package com.ruoyi.query.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.DynamicClassInfo;
import com.ruoyi.query.QueryColumnUtils;
import com.ruoyi.query.QueryUtils;
import com.ruoyi.query.entity.Query;
import com.ruoyi.query.entity.TableQueryColumn;
import com.ruoyi.query.mapper.TableQueryColumnMapper;
import com.ruoyi.query.service.QueryService;
import com.ruoyi.query.service.TableQueryColumnService;
import com.ruoyi.util.DynamicUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 列表查询列 服务实现类
 * </p>
 *
 * @author XiaShiLong
 * @since 2021-03-25
 */
@Service
public class TableQueryColumnServiceImpl extends ServiceImpl<TableQueryColumnMapper, TableQueryColumn> implements TableQueryColumnService {

    private final QueryService queryService;

    @Autowired
    public TableQueryColumnServiceImpl(QueryService queryService) {
        this.queryService = queryService;
    }

    /**
     * 根据menuId获取
     *
     * @param menuId 菜单id
     * @return Optional
     */
    @Override
    public List<TableQueryColumn> get(Long menuId) {
        return this.list(Wrappers.<TableQueryColumn>lambdaQuery().eq(TableQueryColumn::getMenuId, menuId));
    }

    /**
     * 获取所有可查询字段
     *
     * @param menuId    菜单id
     * @param classPath 类路径
     * @return List
     */
    @Override
    public List<TableQueryColumn> getAll(Long menuId, String classPath) {
        List<TableQueryColumn> useList = QueryColumnUtils.getCache(menuId);
        DynamicClassInfo dynamicClassInfo = DynamicUtil.resolveClass(classPath, true);
        List<TableQueryColumn> returnList = new ArrayList<>();
        transform(menuId, returnList, dynamicClassInfo);
        if (!useList.isEmpty()) {
            useList.forEach(
                    t ->
                            returnList.stream()
                                    .filter(r -> equal(t, r))
                                    .forEach(r ->
                                            {
                                                r.use(t.getId());
                                                r.setHovId(t.getHovId());
                                            }
                                    )
            );
        }
        return returnList;
    }

    /**
     * 保存可查询列
     *
     * @param menuId    菜单id
     * @param classPath 类路径
     * @param newList   <see>TableQueryColumn</see>
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveAll(Long menuId, String classPath, List<TableQueryColumn> newList) throws ClassNotFoundException {
        List<TableQueryColumn> oldList = this.list(Wrappers.<TableQueryColumn>lambdaQuery().eq(TableQueryColumn::getMenuId, menuId));
        if (oldList.isEmpty()) {
            return this.saveBatch(newList);
        } else {
            QueryColumnUtils.clearCache(menuId);
            //update
            List<TableQueryColumn> intersection = newList.stream()
                    .filter(oldList::contains)
                    .collect(Collectors.toList());
            if (!intersection.isEmpty()) {
                this.updateBatchById(intersection);
            }
            //remove
            oldList.removeAll(intersection);
            if (!oldList.isEmpty()) {
                List<String> deleteColumnNames = oldList.stream()
                        .map(TableQueryColumn::getAttributeName)
                        .collect(Collectors.toList());
                this.removeByIds(oldList.stream().map(TableQueryColumn::getId).collect(Collectors.toList()));
                String className = Class.forName(classPath).getSimpleName();
                List<Query> cacheUser = QueryUtils.getCacheUserAll(menuId, className);
                List<Query> cacheAdmin = QueryUtils.getCacheAdmin(menuId, className);
                Set<Long> deleteQueryIdList = new HashSet<>();
                cacheUser.addAll(cacheAdmin);
                cacheUser.forEach(
                        q -> q.getDetailList().forEach(
                                d -> {
                                    if (deleteColumnNames.contains(d.getColumnName())) {
                                        deleteQueryIdList.add(q.getId());
                                    }
                                }
                        )
                );
                if (!deleteQueryIdList.isEmpty()) {
                    queryService.removeByIds(deleteQueryIdList);
                }
                QueryUtils.deleteCaCheUserAll(className);
                QueryUtils.deleteCaChe(QueryUtils.adminKey(className));
            }
            //new
            newList.removeAll(intersection);
            if (!newList.isEmpty()) {
                this.saveBatch(newList);
            }
            return true;
        }
    }

    //数据转换
    private void transform(Long menuId, List<TableQueryColumn> tableQueryColumnList, DynamicClassInfo dynamicClassInfo) {
        dynamicClassInfo.getFieldInfoList().forEach(
                f ->
                        tableQueryColumnList.add(
                                TableQueryColumn.builder()
                                        .menuId(menuId)
                                        .tableName(f.getTableName())
                                        .columnName(f.getTableColumnName())
                                        .attributeName(f.getAttributeName())
                                        .nameCh(f.getAttributeNameCh())
                                        .type(f.getType())
                                        .radio(f.isRadio())
                                        .build()
                        )

        );
    }

    //比较相等
    private boolean equal(TableQueryColumn val1, TableQueryColumn val2) {
        return (val1.getTableName() + val1.getColumnName()).equals(val2.getTableName() + val2.getColumnName());
    }

}
